package com.easylinkin.linkappapi.airconditioner.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.airconditioner.entity.AirHostDevice;
import com.easylinkin.linkappapi.airconditioner.entity.AirconditionDevice;
import com.easylinkin.linkappapi.airconditioner.entity.AirconditionDeviceRecord;
import com.easylinkin.linkappapi.airconditioner.mapper.AirconditionDeviceMapper;
import com.easylinkin.linkappapi.airconditioner.service.AirHostDeviceService;
import com.easylinkin.linkappapi.airconditioner.service.AirconditionDeviceRecordService;
import com.easylinkin.linkappapi.airconditioner.service.AirconditionDeviceService;
import com.easylinkin.linkappapi.common.utils.excel.ExcelConstant;
import com.easylinkin.linkappapi.common.utils.excel.ExcelReadUtil;
import com.easylinkin.linkappapi.common.utils.excel.ExcelTools;
import com.easylinkin.linkappapi.common.utils.io.OutputStreamUtil;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.device.service.DeviceService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

@Service
public class AirconditionDeviceServiceImpl extends ServiceImpl<AirconditionDeviceMapper, AirconditionDevice> implements AirconditionDeviceService {
    private static final Logger LOGGER = LoggerFactory.getLogger(AirconditionDeviceServiceImpl.class);
    private static final int PARSE_EXCEL_START_ROW = 1;
    private static final int CONTENT_IN_EXCEL_START_ROW = 1;
    @Resource
    DeviceService deviceService;
    @Resource
    AirHostDeviceService airHostDeviceService;
    @Resource
    AirconditionDeviceRecordService airconditionDeviceRecordService;
    @Resource
    LinkappUserContextProducer linkappUserContextProducer;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchInsert(List<AirconditionDevice> list) {
        if(list == null || list.size()<=0){
            return;
        }
        String tenantId=linkappUserContextProducer.getNotNullCurrent().getTenantId();
        List<String> ids=list.stream().map(i->i.getDeviceId()).collect(Collectors.toList());
        if(ids == null || ids.size()<=0){
            return;
        }
        String hostDeviceId=list.get(0).getHostDeviceId();
        Assert.notNull(hostDeviceId,"未检测到主机设备");
        //查询是否存在设备
        QueryWrapper<Device> drqw=new QueryWrapper<>();
        drqw.eq("tenant_id",tenantId);
        drqw.in("code",ids);
        List<Device> deviceList=deviceService.list(drqw);
        Assert.notEmpty(deviceList,"设备"+JSON.toJSONString(ids)+"不存在");
        //求差集
        if(deviceList.size() != ids.size()){
            List<String> deviceCodes=deviceList.stream().map(i->i.getCode()).collect(Collectors.toList());
            List<String> filterIds=ids.stream().filter(item->!deviceCodes.contains(item)).collect(Collectors.toList());
            if(filterIds.size()>0){
                Assert.isTrue(false,"设备"+JSON.toJSONString(filterIds)+"不存在");
            }
            //交集
            filterIds=ids.stream().filter(item->deviceCodes.contains(item)).collect(Collectors.toList());
            if(filterIds.size()>0){
                Assert.isTrue(false,"设备"+JSON.toJSONString(filterIds)+"已绑定");
            }
        }
        //检查主机表
        QueryWrapper<AirHostDevice> qwHost=new QueryWrapper<>();
        qwHost.in("device_id",ids).or().in("wattmeter_id",ids);
        qwHost.eq("tenant_id",tenantId);
        List<AirHostDevice> airHostDeviceList=airHostDeviceService.list(qwHost);
        if(airHostDeviceList != null && airHostDeviceList.size()>0){
            //求交集
            List<String> hostIds=airHostDeviceList.stream().map(i->i.getDeviceId()).collect(Collectors.toList());
            List<String> filterIds=ids.stream().filter(item->hostIds.contains(item)).collect(Collectors.toList());
            if(filterIds.size()>0){
                Assert.isTrue(false,"设备"+JSON.toJSONString(filterIds)+"已绑定");
            }
        }

        //检查子设备是否存在
        QueryWrapper<AirconditionDevice> qw=new QueryWrapper<>();
        qw.in("device_id",ids);
        qw.eq("tenant_id",tenantId);
        List<AirconditionDevice> airconditionDeviceList=baseMapper.selectList(qw);
        if(airconditionDeviceList != null && airconditionDeviceList.size()>0){
            //求交集
            List<String> hostIds=airconditionDeviceList.stream().map(i->i.getDeviceId()).collect(Collectors.toList());
            List<String> filterIds=ids.stream().filter(item->hostIds.contains(item)).collect(Collectors.toList());
            if(filterIds.size()>0){
                Assert.isTrue(false,"设备"+JSON.toJSONString(filterIds)+"已绑定");
            }
        }
        //批量添加
        Date date=new Date();
        list=list.stream().map(i->{i.setCreateTime(date);i.setUpdateTime(date);i.setTenantId(tenantId);return i;}).collect(Collectors.toList());
        baseMapper.batchInsert(list);

    }

    @Override
    public IPage<AirconditionDevice> getPage(IPage<AirconditionDevice> page,AirconditionDevice airconditionDevice) {
        Assert.notNull(airconditionDevice,"参数为空！");
        Assert.notNull(airconditionDevice.getHostDeviceId(),"hostDeviceId为空");
        QueryWrapper<AirconditionDevice> qw=new QueryWrapper();
        qw.eq("tenant_id",linkappUserContextProducer.getNotNullCurrent().getTenantId());
        qw.eq("host_device_id",airconditionDevice.getHostDeviceId());
        qw.orderByDesc("update_time");
        return baseMapper.selectPage(page,qw);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDeviceFan(AirconditionDevice airconditionDevice) {
        Assert.notNull(airconditionDevice,"参数为空！");
        Assert.notNull(airconditionDevice.getHostDeviceId(),"hostDeviceId参数为空!");
        Assert.notEmpty(airconditionDevice.getDeviceIds(),"deviceIds参数为空!");
        QueryWrapper<AirconditionDevice> qw=new QueryWrapper();
        qw.eq("tenant_id",linkappUserContextProducer.getNotNullCurrent().getTenantId());
        qw.in("device_id",airconditionDevice.getDeviceIds());
        airconditionDevice.setUpdateTime(new Date());
        baseMapper.update(airconditionDevice,qw);
    }

    @Override
    public List<AirconditionDevice> getHostLowerAirconditionDeviceAll(AirconditionDevice airconditionDevice) {
        Assert.notNull(airconditionDevice,"参数为空!");
        Assert.notNull(airconditionDevice.getHostDeviceId(),"参数为空!");
        QueryWrapper<AirconditionDevice> qw=new QueryWrapper<>();
        if(airconditionDevice.getTenantId() == null){
            qw.eq("tenant_id",linkappUserContextProducer.getNotNullCurrent().getTenantId());
        }else{
            qw.eq("tenant_id",airconditionDevice.getTenantId());
        }
        qw.eq("host_device_id",airconditionDevice.getHostDeviceId());
        qw.orderByDesc("update_time");
        return baseMapper.selectList(qw);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeHostLowerAirconditionDeviceById(AirconditionDevice airconditionDevice) {
        Assert.notNull(airconditionDevice,"参数为空!");
        Assert.notNull(airconditionDevice.getHostDeviceId(),"hostDeviceId参数为空!");
        Assert.notEmpty(airconditionDevice.getDeviceIds(),"deviceIds参数为空!");
        String tenantId=linkappUserContextProducer.getNotNullCurrent().getTenantId();
        QueryWrapper<AirconditionDeviceRecord> qw=new QueryWrapper<>();
        qw.eq("tenant_id",tenantId);
        qw.in("aircondition_device_id",airconditionDevice.getDeviceIds());
        //删除设备数据
        airconditionDeviceRecordService.remove(qw);
        //删除设备
        QueryWrapper<AirconditionDevice> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("tenant_id",tenantId);
        queryWrapper.in("device_id",airconditionDevice.getDeviceIds());
        baseMapper.delete(queryWrapper);
    }


    @Override
    public void getImportTemplate(HttpServletRequest request, HttpServletResponse response) {
        String title = "主机-空调批量绑定模板";
        String fileName = title + ".xls";
        try {
            OutputStream outputStream = OutputStreamUtil
                    .getOutputStream(request, response, fileName);
            String keyValue = "主机编码(必填):hostDeviceId,空调编码(必填):deviceId,高风功率:highFan,中风功率:midFan,低风功率:lowFan";
            ExcelTools
                    .exportExcel(outputStream, keyValue, inits(), ExcelConstant.XLS,
                            title);
            response.flushBuffer();
            outputStream.close();
        } catch (IOException e) {
            LOGGER.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！IOException异常");
        } catch (Exception e) {
            LOGGER.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！");
        }

    }

    public List<AirconditionDevice> inits(){
        return Arrays.asList(new AirconditionDevice()
        .setHostDeviceId("A202105191217004")
        .setDeviceId("2021051716170017")
        .setHighFan(new BigDecimal(1.2).setScale(2,BigDecimal.ROUND_HALF_UP))
        .setMidFan(new BigDecimal(0.7).setScale(2,BigDecimal.ROUND_HALF_UP))
        .setLowFan(new BigDecimal(0.2).setScale(2,BigDecimal.ROUND_HALF_UP)));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Set importData(MultipartFile file) {
        Set deviceErrorList = new HashSet();
        List<AirconditionDevice> list = getImportData(getContentList(file), deviceErrorList);
        //saveBatch(list);
        if(list != null && list.size()>0){
            baseMapper.batchInsert(list);
        }
        return deviceErrorList;
    }

    /***
     * 根据ID查询是否存在
     * @param deviceId
     * @return
     */
    private Integer getAirHostDeviceIfExists(String deviceId,String tenantId){
        //检查主机表是否存在
        QueryWrapper<AirHostDevice> qw=new QueryWrapper<>();
        qw.eq("tenant_id",tenantId);
        qw.eq("device_id",deviceId);
        Integer count=airHostDeviceService.count(qw);
        if(count<=0){
            return null;
        }
        return count;
    }

    @Override
    public AirconditionDevice getById(String deviceId){
        //检查设备表是否存在
        QueryWrapper<AirconditionDevice> qw=new QueryWrapper<>();
        qw.eq("tenant_id",linkappUserContextProducer.getNotNullCurrent().getTenantId());
        qw.eq("device_id",deviceId);
        return baseMapper.selectOne(qw);
    }

    /***
     * 根据ID查询是否存在
     * @param deviceId
     * @return
     */
    private AirconditionDevice getAirconditionDeviceIfExists(String deviceId,String tenantId){
        if(org.springframework.util.StringUtils.isEmpty(deviceId)){
            return null;
        }
        //检查设备表是否存在
        QueryWrapper<Device> deviceqw=new QueryWrapper();
        deviceqw.eq("code",deviceId);
        deviceqw.eq("tenant_id",tenantId);
        Device device=deviceService.getOne(deviceqw);
        if(device == null){
            return null;
        }
        //检查主机表是否存在
        QueryWrapper<AirHostDevice> qwHost=new QueryWrapper<>();
        qwHost.eq("tenant_id",tenantId);
        qwHost.eq("device_id",deviceId).or().eq("wattmeter_id",deviceId);
        Integer count=airHostDeviceService.count(qwHost);
        if(count>0){
            return null;
        }
        //检查子设备表是否存在
        QueryWrapper<AirconditionDevice> qw=new QueryWrapper<>();
        qw.eq("device_id",deviceId);
        qw.eq("tenant_id",tenantId);
        AirconditionDevice airconditionDevice=baseMapper.selectOne(qw);
        if(airconditionDevice != null){
            return null;
        }
        airconditionDevice=new AirconditionDevice();
        airconditionDevice.setDeviceId(device.getId());
        airconditionDevice.setDeviceCode(device.getCode());
        airconditionDevice.setDeviceName(device.getName());
        return airconditionDevice;
    }

    private List<AirconditionDevice> getImportData(List<List<String>> contentList, Set deviceErrorList) {
        AirconditionDevice device;
        String value;
        List<AirconditionDevice> devices = new ArrayList<>();
        Date date=new Date();
        String tenantId=linkappUserContextProducer.getNotNullCurrent().getTenantId();
        for (int row = CONTENT_IN_EXCEL_START_ROW; row < contentList.size(); row++) {
            try {
                boolean loop = true;
                device = new AirconditionDevice();
                for (int i = 0; i < contentList.get(row).size() && loop; i++) {
                    value = StringUtils.isEmpty(contentList.get(row).get(i))
                            || StringUtils.isEmpty(contentList.get(row).get(i).trim())
                            ? null : contentList.get(row).get(i).trim();
                    switch (i) {
                        case 0:
                            Integer count= getAirHostDeviceIfExists(value,tenantId);
                            if (count != null && count>0) {
                                device.setHostDeviceId(value);
                            } else {
                                deviceErrorList.add(row);
                                loop = false;
                            }
                            break;
                        case 1:
                            AirconditionDevice airconditionDevice = getAirconditionDeviceIfExists(value,tenantId);
                            if (airconditionDevice != null) {
                                device.setDeviceId(value);
                                device.setDeviceName(airconditionDevice.getDeviceName());
                                device.setDeviceCode(airconditionDevice.getDeviceCode());
                            } else {
                                deviceErrorList.add(row);
                                loop = false;
                            }
                            break;
                        case 2:
                            if (null != value) {
                                device.setHighFan(BigDecimal.valueOf(Double.valueOf(value)));
                            }
                            break;
                        case 3:
                            if (null != value) {
                                device.setMidFan(BigDecimal.valueOf(Double.valueOf(value)));
                            }
                            break;
                        case 4:
                            if (null != value) {
                                device.setLowFan(BigDecimal.valueOf(Double.valueOf(value)));
                            }
                            break;
                        default:
                            break;
                    }
                }
//				validParamRequired(device);
//				validParamFormat(device);
                if (loop) {
                    // 设置租户id
                  device.setTenantId(tenantId);
                  device.setUpdateTime(date);
                  device.setCreateTime(date);
                  devices.add(device);
                }
            } catch (Exception e) {
                deviceErrorList.add(row);
                continue;
            }
        }
        return devices;
    }


    private List<List<String>> getContentList(MultipartFile file) {

        List<List<String>> contentList = ExcelReadUtil
                .getExcelInfo(file, PARSE_EXCEL_START_ROW, null, -1);

        //验证导入文件 是否使用了正确的模板，以及表格第一列是否缺失或多了字段
        Map<Integer, String> standardHeaderRow = new HashMap<>(6);

        String keyValue = "主机编码(必填):hostDeviceId,空调编码(必填):deviceId,高风功率:highFan,中风功率:midFan,低风功率:lowFan";
        List<String> keys = Arrays.asList(StringUtils.split(keyValue, ",")).stream().map(s -> s = s.substring(0, s.indexOf(":"))).collect(Collectors.toList());
        for (int i = 0; i < keys.size(); i++) {
            standardHeaderRow.put(i, keys.get(i));
        }

        StringUtils.split(",");
        //根据表头判断是否使用了正确的模板
        ExcelReadUtil.validateExeclTemplet(contentList, 0, standardHeaderRow);

        int[] requiredColumnIndexes = {0, 1};

        int errorNum = ExcelReadUtil.validateRequiredFields(contentList, requiredColumnIndexes);
        if (errorNum != -1) {
            throw new RuntimeException("第" + (errorNum + CONTENT_IN_EXCEL_START_ROW) + "行,必填写列为空");
        }
        return contentList;
    }
}

